/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.wsinfra.wsr.storage.impl;


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;

import org.apache.xmlbeans.GDuration;

import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.wsr.impl.WsrUtil;
import cgl.narada.wsinfra.wsr.storage.WsrGroupInfoStorageOperations;
import cgl.narada.wsinfra.wsr.storage.WsrStorageException;
/**
 * @author Sima Patel
 * $Date: 2005/03/18 20:18:23 $
 * $Revision: 1.3 $
 * Description: Handles Group Info Storage operations
 */

public class WsrGroupInfoStorageOperationsImpl implements 
                                               WsrGroupInfoStorageOperations {

    private WsrQueryHandler wsrQueryHandler;
    private WsrUtil wsrUtil;
    private String moduleName = "WsrGroupInfoStorageOperationsImpl: ";

    public WsrGroupInfoStorageOperationsImpl() {}

    public WsrGroupInfoStorageOperationsImpl(Connection connection) {
        wsrQueryHandler = new WsrQueryHandler(connection);
        wsrUtil = WsrUtil.getInstance();
    }

    /* Stores the GroupId that should be used while communicating
    with a given destination (based on the contents of the wsa:To element).
    This feature allows us to send messages reliably with minimal
    intervention from the application.*/
    public void addDestinationGroupIdPair(String destination,
                                          String groupId) 
                throws WsrStorageException {

        String query = "insert into wsrgroupdestinationinfo values('" +
                        groupId + "'," + "'" + destination + "')";

        PreparedStatement pstmt =
        wsrQueryHandler.getPreparedStatement(query);
        try {
            pstmt.executeUpdate();
            pstmt.close();

        }
        catch (SQLException ex) {
            throw new WsrStorageException(moduleName +
            "addDestinationGroupIdPair exception ["
            + query + "] " + ex.toString());
        }

    }
    /* Retrieve the groupIds for a specific destination */
    public String[] getGroupIdsForDestination(String destination) 
                    throws WsrStorageException {
        String query = 
            "select groupId from wsrgroupdestinationinfo where destination='"
            + destination + "'";

        PreparedStatement preparedStatement = 
                wsrQueryHandler.getPreparedStatement(query);
        ResultSet resultSet = wsrQueryHandler.getResultSet(preparedStatement);
        String[] groupIds = wsrQueryHandler.getStringArray(resultSet);
        wsrQueryHandler.closeResultSet(resultSet);
        wsrQueryHandler.closePreparedStatement(preparedStatement);
        return groupIds;
    }

    /* Retrieves the destination for a specific groupId */
    public String getDestinationForGroupId(String groupId) 
                  throws WsrStorageException {
        String query =
               "select destination from wsrgroupdestinationinfo where groupId='"
               + groupId + "'";
        PreparedStatement preparedStatement = 
              wsrQueryHandler.getPreparedStatement(query);
        ResultSet resultSet = wsrQueryHandler.getResultSet(preparedStatement);
        String destination = null;
        try {
            while (resultSet.next()) {
                destination = resultSet.getString(1);
            }
        }catch (SQLException ex) {
            throw new WsrStorageException(moduleName +
            "getGroupIdForDestination exception ["
            + query + "] " + ex.toString());

        }
        wsrQueryHandler.closeResultSet(resultSet);
        wsrQueryHandler.closePreparedStatement(preparedStatement);
        return destination;
    }

    /* Removes the destination/sequence identifier pair corresponding to this
    destination */
    public void removeDestinationGroupIdPair(String groupId)
                throws WsrStorageException {

        String query = "delete from wsrgroupdestinationinfo where groupId='"
                       + groupId + "'";
        int row = wsrQueryHandler.updateQuery(query);
       
    }

    /** Checks to see if there is a groupId/destination pair corresponding
    to the destination in question. */
    public boolean hasGroupIdForDestination(String destination)
                   throws WsrStorageException {

        String query =
        "select count(*) from wsrgroupdestinationinfo where destination='"
        + destination.trim() + "'";
        return (wsrQueryHandler.getLongNumber(query) > 0);

    }
    /* Retrieves the sequence number that was last Delivered on a given
    group. This method throws an exception if the group
    specified by groupId is an unknown one or if there are 
    storage related problems.  */
    public long getSequenceNumberLastDelivered(String groupId)
                throws WsrStorageException{

        String query =
            "select sequenceNumberLastDelivered from wsrgroupinfo where groupId='"
            + groupId + "'";
        long sequenceNumber = wsrQueryHandler.getLongNumber(query);
        return sequenceNumber;
    }


    /** A method which checks whether a certain group (irrespective of whether
    it is active/terminated/expired/timed-out) is a known group at this
    node */
    public boolean isKnownGroup(String groupId) throws WsrStorageException {
        String query =
        "select count(*) from wsrgroupdestinationinfo where groupId='"
        + groupId + "'";

        return (wsrQueryHandler.getLongNumber(query) > 0);

    }
    /* A method which checks whether a certain group (irrespective of whether
    it is active/terminated/expired/timed-out) is a exits(from Sink point of view) at this
    node */
    public boolean isGroupExists(String groupId) 
                   throws WsrStorageException{
	String query1 =
            "select groupId from wsrgroupinfo where groupId='"
            + groupId + "'";
	PreparedStatement preparedStatement = 
                wsrQueryHandler.getPreparedStatement(query1);
        ResultSet resultSet = wsrQueryHandler.getResultSet(preparedStatement);
        String[] groupIds = wsrQueryHandler.getStringArray(resultSet);
        wsrQueryHandler.closeResultSet(resultSet);
        wsrQueryHandler.closePreparedStatement(preparedStatement);
        for(int i =0; i<groupIds.length; i++){
	    System.out.println("****** got groupid********");
	    System.out.println(groupIds[i]);
	}

    	String query =
            "select count(*) from wsrgroupinfo where groupId='"
            + groupId + "'";
        
            return (wsrQueryHandler.getLongNumber(query) > 0);
    	
    }
    /* Store a GroupInfo object. This method throws an exception under the
    following circumstances
    <br> Storage related problems */
    public void storeCreatedGroup(WsrGroupInfoImpl wsrGroupInfo) 
                throws WsrStorageException {
        String groupId = wsrGroupInfo.getGroupId();
        boolean hasGroupExpiryTime = wsrGroupInfo.hasGroupExpiryTime();
        Calendar groupExpiryTime = null;
        if(hasGroupExpiryTime){
            groupExpiryTime = wsrGroupInfo.getGroupExpiryTime();  
        }
        boolean hasGroupMaxIdleDuration = wsrGroupInfo.hasGroupMaxIdleDuration();
        GDuration groupMaxIdleDuration = null;
        if(hasGroupMaxIdleDuration){
            groupMaxIdleDuration = wsrGroupInfo.getGroupMaxIdleDuration();  
        }
        boolean hasLastSequenceNumber = wsrGroupInfo.hasLastSequenceNumber();
        long lastSequenceNumber =0;
        if(hasLastSequenceNumber){
            lastSequenceNumber = wsrGroupInfo.getLastSequenceNumber();
        }
        long sequenceNumberLastDelivered = 
                                  wsrGroupInfo.getSequenceNumberLastDelivered();
        boolean isSource = wsrGroupInfo.isSource();
        EndpointReferenceType source = wsrGroupInfo.getSource();
        EndpointReferenceType destination = wsrGroupInfo.getDestination();
        byte[] marshalledBytesOfAddresses = wsrGroupInfo.getBytesOfAddresses();

        String query = "select count(*) from wsrgroupinfo where groupId='"
                        + groupId + "'";
        boolean initialDataCreation = false;

        if (wsrQueryHandler.getLongNumber(query) <= 0) {
            initialDataCreation = true;
        }
        if (initialDataCreation) {
            query = "insert into wsrgroupinfo  values('" + groupId + "',"
              + wsrQueryHandler.getIntOfBoolean(hasGroupExpiryTime) + ",'" +
              wsrUtil.getStringOfCalendar(groupExpiryTime) + "'," +
              wsrQueryHandler.getIntOfBoolean(hasGroupMaxIdleDuration) + ",'" +
              wsrUtil.getStringOfDuration(groupMaxIdleDuration) + "'," +
              wsrQueryHandler.getIntOfBoolean(hasLastSequenceNumber) + "," +
              lastSequenceNumber + ","+ sequenceNumberLastDelivered+","+
              wsrQueryHandler.getIntOfBoolean(isSource)+",?)";
        }
        else {

            query = "update wsrgroupinfo  set " +
              "hasGroupExpiryTime = " + wsrQueryHandler.getIntOfBoolean
                                                         (hasGroupExpiryTime) +
              ", groupExpiryTime = '" +
              wsrUtil.getStringOfCalendar(groupExpiryTime) +
              "', hasGroupMaxIdleDuration = " +
              wsrQueryHandler.getIntOfBoolean(hasGroupMaxIdleDuration) +
              ", groupMaxIdleDuration = '" +
              wsrUtil.getStringOfDuration(groupMaxIdleDuration) +
              "', hasLastSequenceNumber = " +
              wsrQueryHandler.getIntOfBoolean(hasLastSequenceNumber) +
              ", lastSequenceNumber = " + lastSequenceNumber +
			  ", sequenceNumberLastDelivered = " + sequenceNumberLastDelivered +
			  ", isSource = " + 
			  wsrQueryHandler.getIntOfBoolean(isSource)+ 
              ", marshalledBytesOfAddresses = ?" +
              " where groupId='" + groupId + "'";
        }
        PreparedStatement pstmt1 = wsrQueryHandler.getPreparedStatement(query);
        try {
            pstmt1.setBytes(1, marshalledBytesOfAddresses);
            pstmt1.executeUpdate();
            pstmt1.close();
        }
        catch (SQLException ex) {
            throw new WsrStorageException(moduleName +
                                                 "storeCreatedGroup exception ["
                                                + query + "] " + ex.toString());
        }
        
    }

    /* Retrieves the GroupInfo corresponding to the specified 
    groupId. This method throws an exception under the following conditions.
    <br> The Group specified in groupId is an unknown one.
    <br> Storage related problems */
    public WsrGroupInfoImpl getGroupInfoUsingGroupId(String groupId)
                            throws WsrStorageException{
        WsrGroupInfoImpl wsrGroupInfoImpl=null;
        String query = "select * from wsrgroupinfo where groupId='"
                        + groupId + "'";
        try{
            PreparedStatement preparedStatement =
                     wsrQueryHandler.getPreparedStatement(query);
            ResultSet resultSet = wsrQueryHandler.getResultSet(
                                                             preparedStatement);
            while(resultSet.next()){
                boolean hasGroupExpiryTime = 
                                     resultSet.getBoolean("hasGroupExpiryTime");
                Calendar groupExpiryTime = wsrUtil.getCalendarOfString(
                            resultSet.getString("groupExpiryTime"));
                
                boolean hasGroupMaxIdleDuration = resultSet.getBoolean(
                                                     "hasGroupMaxIdleDuration");
                GDuration groupMaxIdleDuration=null;
                if(hasGroupMaxIdleDuration){
                groupMaxIdleDuration = 
                	wsrUtil.getDurationOfString(
                        resultSet.getString("groupMaxIdleDuration"));
                
                }
                boolean hasLastSequenceNumber = resultSet.getBoolean(
                                                       "hasLastSequenceNumber");
                long lastSequenceNumber=resultSet.getLong("lastSequenceNumber");
                long sequenceNumberLastDelivered = resultSet.getLong
                ("sequenceNumberLastDelivered");
                boolean isSource = resultSet.getBoolean("isSource");
                byte[] marshalledBytesOfAddresses = resultSet.getBytes(
                                                  "marshalledBytesOfAddresses");
                wsrGroupInfoImpl =  new WsrGroupInfoImpl(groupId, isSource, 
                                                    marshalledBytesOfAddresses);
                if(hasGroupExpiryTime){
                    wsrGroupInfoImpl.setGroupExpiryTime(groupExpiryTime);
                }

                if(hasGroupMaxIdleDuration){
                    wsrGroupInfoImpl.setGroupMaxIdleDuration(
                                                          groupMaxIdleDuration);
                }

                if(hasLastSequenceNumber){
                    wsrGroupInfoImpl.setLastSequenceNumber(lastSequenceNumber);
                }
                wsrGroupInfoImpl.setSequenceNumberLastDelivered(
                                                   sequenceNumberLastDelivered);
            }
        }catch(SQLException se){
            se.printStackTrace();
             throw new WsrStorageException
                        (moduleName + "getGroupInfoUsingGroupId exception ["
                         + "] " + se.toString());
        }
        return wsrGroupInfoImpl;
    }
    /* Removes the GroupInfo corresponding to the specified 
    groupId. This method throws an exception under the following conditions.
    <br> The Group specified in groupId is an unknown one.
    <br> Storage related problems */
    public void deleteGroupInfo(String groupId) throws WsrStorageException{
        String query = "delete from wsrgroupinfo where groupId='"
                       + groupId + "'";
        int row = wsrQueryHandler.updateQuery(query);
        
      
    }
    private String[] getQueryResultForGroupInfoId(String query) 
                     throws WsrStorageException {
        PreparedStatement preparedStatement =
                                   wsrQueryHandler.getPreparedStatement(query);
        ResultSet resultSet = wsrQueryHandler.getResultSet(preparedStatement);

        String[] resultString = wsrQueryHandler.getStringArray(resultSet);
        wsrQueryHandler.closeResultSet(resultSet);
        wsrQueryHandler.closePreparedStatement(preparedStatement);
        return resultString;

    }
   
    /* Retrieves the entire list of groupIds
    registered with the underlying service. This method throws an exception 
    if  there are storage related problems. */
    public String[] getListOfAllGroups(boolean isSource) 
                    throws WsrStorageException {
        String query =
            "select groupId from wsrgroupinfo where isSource =" +
            wsrQueryHandler.getIntOfBoolean(isSource);
        return getQueryResultForGroupInfoId(query);

    }
  
}
